﻿/*********************************************************
 * 开发人员：小兵
 * 创建时间：2012-10-25 13:52:47
 * 描述说明：
 * 
 * 更改历史：
 * 
 * *******************************************************/
namespace Mozlite.Components
{
    using System;
    using System.Web;
    using System.Data;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// 分类管理。
    /// </summary>
    public abstract class Categories<T> where T : BaseCategory<T>, new()
    {
        #region methods
        private static string GetCacheKey(string tableName, string culture)
        {
            return "Categories::" + tableName + "::" + culture;
        }
        /// <summary>
        /// 分类列表。
        /// </summary>
        /// <param name="cultureName">区域。</param>
        /// <returns>返回分类列表实例。</returns>
        public static Dictionary<int, T> GetCategories(string cultureName)
        {
            Guard.IsNotNullOrEmpty(cultureName, "cultureName");
            var table = new T().TableName;
            return Caches.Get<Dictionary<int, T>>(GetCacheKey(table, cultureName), Consts.MinuteSeconds * 3, Consts.MinuteSeconds * 3, () =>
            {
                var categories = new Dictionary<int, T>();
                categories.Add(0, new T { CategoryName = Globals.ToLocal("Categories_TopLevel") });
                using(var reader = Database.ExecuteReader("SELECT * FROM {0} WHERE CultureName = @CultureName ORDER BY ParentID, SortOrder".FormatWith(table), new { CultureName = cultureName }))
                {
                    while(reader.Read())
                    {
                        var category = reader.As<T>();
                        categories.Add(category.CategoryID, category);
                    }
                    reader.Close();
                }
                return categories;
            });
        }
        /// <summary>
        /// 分类列表。
        /// </summary>
        /// <param name="cultureName">区域。</param>
        /// <returns>返回分类列表实例。</returns>
        public static Dictionary<int, List<T>> GetCategoriesByParentID(string cultureName)
        {
            Guard.IsNotNullOrEmpty(cultureName, "cultureName");
            var table = new T().TableName;
            string cacheKey = "CategoriesByParentID::" + table + "::" + cultureName;
            return Caches.Get<Dictionary<int, List<T>>>(cacheKey, () =>
            {
                var categories = new Dictionary<int, List<T>>();
                using(var reader = Database.ExecuteReader("SELECT * FROM {0} WHERE CultureName = @CultureName ORDER BY ParentID, SortOrder".FormatWith(table), new { CultureName = cultureName }))
                {
                    while(reader.Read())
                    {
                        var category = reader.As<T>();
                        if(!categories.ContainsKey(category.ParentID))
                            categories.Add(category.ParentID, new List<T>());
                        categories[category.ParentID].Add(category);
                    }
                    reader.Close();
                }
                Caches.Insert(cacheKey, categories, new System.Web.Caching.CacheDependency(null, new string[] { GetCacheKey(table, cultureName) }));
                return categories;
            });
        }
        /// <summary>
        /// 保存分类。
        /// </summary>
        /// <typeparam name="T">分类类型。</typeparam>
        /// <param name="category">分类实例。</param>
        /// <returns>返回保存结果。</returns>
        internal static bool Save(T category)
        {
            bool isSaved = false;
            if(category.CategoryID > 0)
            {
                var src = GetCategory(category.CategoryID, category.CultureName);
                if(src.ParentID != category.ParentID)
                    category.SortOrder = GetSortOrder(category.ParentID, category.CultureName);
                isSaved = Database.ExecuteNonQuery("UPDATE {0} SET CategoryKey = @CategoryKey, CategoryName = @CategoryName, ParentID = @ParentID, LogoUrl = @LogoUrl, SortOrder = @SortOrder, LastUpdateDate = GETDATE(), Description = @Description, DefaultUrlFormat = @DefaultUrlFormat, PagerUrlFormat = @PagerUrlFormat, DetailUrlFormat = @DetailUrlFormat, RoleLevel = @RoleLevel WHERE CategoryID = @CategoryID AND CultureName = @CultureName;".FormatWith(category.TableName), new
                {
                    CategoryKey = category.CategoryKey,
                    CategoryName = category.CategoryName,
                    ParentID = category.ParentID,
                    LogoUrl = category.LogoUrl,
                    SortOrder = category.SortOrder,
                    Description = category.Description,
                    DefaultUrlFormat = category.DefaultUrlFormat,
                    PagerUrlFormat = category.PagerUrlFormat,
                    DetailUrlFormat = category.DetailUrlFormat,
                    CultureName = category.CultureName,
                    RoleLevel = category.RoleLevel,
                    CategoryID = category.CategoryID
                });
            }
            else
            {
                isSaved = Database.ExecuteNonQuery("INSERT INTO {0}(CategoryKey, CategoryName, ParentID, CultureName,LogoUrl,SortOrder,CreateDate,LastUpdateDate, Description, DefaultUrlFormat, PagerUrlFormat, DetailUrlFormat, ModuleID, RoleLevel)VALUES(@CategoryKey,@CategoryName,@ParentID,@CultureName,@LogoUrl,@SortOrder,GETDATE(),GETDATE(),@Description, @DefaultUrlFormat, @PagerUrlFormat, @DetailUrlFormat, @ModuleID, @RoleLevel);".FormatWith(category.TableName), new
                {
                    CategoryKey = category.CategoryKey,
                    CategoryName = category.CategoryName,
                    ParentID = category.ParentID,
                    CultureName = category.CultureName,
                    LogoUrl = category.LogoUrl,
                    SortOrder = GetSortOrder(category.ParentID, category.CultureName),//category.SortOrder,
                    Description = category.Description,
                    DefaultUrlFormat = category.DefaultUrlFormat,
                    PagerUrlFormat = category.PagerUrlFormat,
                    DetailUrlFormat = category.DetailUrlFormat,
                    ModuleID = category.ModuleID,
                    RoleLevel = category.RoleLevel
                });
            }
            if(isSaved)
                Caches.Remove(GetCacheKey(category.TableName, category.CultureName));
            return isSaved;
        }
        /// <summary>
        /// 判断键是否存在。
        /// </summary>
        /// <param name="category">内容实例。</param>
        /// <returns>返回键是否存在。</returns>
        internal static bool IsKeyExisted(T category)
        {
            if(category.CategoryID > 0)
                return Database.ExecuteScalar<bool>("SELECT 1 FROM {0} WHERE CategoryKey = @CategoryKey AND CultureName = @CultureName AND CategoryID <> @CategoryID;".FormatWith(category.TableName), new { CategoryKey = category.CategoryKey, CultureName = category.CultureName, CategoryID = category.CategoryID });
            return Database.ExecuteScalar<bool>("SELECT 1 FROM {0} WHERE CategoryKey = @CategoryKey AND CultureName = @CultureName;".FormatWith(category.TableName), new { CategoryKey = category.CategoryKey, CultureName = category.CultureName });
        }
        /// <summary>
        /// 删除分类，并且会删除分类下面的项。
        /// </summary>
        /// <typeparam name="TModule">分类模型类型。</typeparam>
        /// <param name="categoryIDs">分类ID集合，多个使用","分割。</param>
        /// <param name="cultureName">资源名称。</param>
        /// <returns>返回执行结果。</returns>
        public static bool Delete<TModule>(string categoryIDs, string cultureName) where TModule : BaseContentModule<TModule>, new()
        {
            var module = new TModule();
            if (Database.BeginTransaction<bool>(transaction =>
            {
                transaction.ExecuteNonQuery("DELETE FROM {0} WHERE CategoryID{1} AND CultureName = @CultureName".FormatWith(module.ItemTableName, categoryIDs.FormatIDs()), new { CultureName = cultureName });
                return transaction.ExecuteNonQuery("DELETE FROM {0} WHERE CategoryID{1} AND CultureName = @CultureName".FormatWith(module.CategoryTableName, categoryIDs.FormatIDs()), new { CultureName = cultureName });
            }))
            {
                Caches.Remove(GetCacheKey(module.CategoryTableName, cultureName));
                return true;
            }
            return false;
        }

        internal static bool IsNameExisted(T category)
        {
            if(category.CategoryID>0)
                return Database.ExecuteScalar<bool>("SELECT 1 FROM {0} WHERE ParentID = @ParentID AND CultureName = @CultureName AND CategoryName = @CategoryName AND CategoryID <> @CategoryID;".FormatWith(category.TableName), new
                {
                    ParentID = category.ParentID,
                    CultureName = category.CultureName,
                    CategoryName = category.CategoryName,
                    CategoryID = category.CategoryID
                });
            return Database.ExecuteScalar<bool>("SELECT 1 FROM {0} WHERE ParentID = @ParentID AND CultureName = @CultureName AND CategoryName = @CategoryName;".FormatWith(category.TableName), new
            {
                ParentID = category.ParentID,
                CultureName = category.CultureName,
                CategoryName = category.CategoryName
            });
        }
        #endregion

        #region get
        /// <summary>
        /// 从缓存中获取分类实例。
        /// </summary>
        /// <param name="id">分类ID。</param>
        /// <param name="cultureName">区域。</param>
        /// <returns>返回分类实例。</returns>
        public static T GetCategory(int id, string cultureName)
        {
            T category;
            GetCategories(cultureName).TryGetValue(id, out category);
            return category;
        }
        /// <summary>
        /// 从数据库中获取分类实例。
        /// </summary>
        /// <param name="key">分类ID。</param>
        /// <param name="cultureName">区域。</param>
        /// <returns>返回分类实例。</returns>
        public static T GetCategory(string key, string cultureName)
        {
            return Database.ExecuteReader<T>("SELECT * FROM {0} WHERE CategoryKey = @CategoryKey AND CultureName = @CultureName".FormatWith(new T().TableName), new
            {
                CategoryKey = key,
                CultureName = cultureName
            });
        }
        #endregion

        #region sort
        /// <summary>
        /// 获取当前排序号码。
        /// </summary>
        /// <typeparam name="T">分类类型。</typeparam>
        /// <param name="parentID">父分类ID。</param>
        /// <param name="cultureName">区域。</param>
        /// <returns>返回排序号码。</returns>
        public static int GetSortOrder(int parentID, string cultureName)
        {
            var table = new T().TableName;
            return Database.GetSortOrder(table, "ParentID = @ParentID AND CultureName = @CultureName", new { ParentID = parentID, CultureName = cultureName });
        }
        /// <summary>
        /// 排序。
        /// </summary>
        /// <typeparam name="T">分类类别。</typeparam>
        /// <param name="category">分类实例。</param>
        /// <param name="isDown">向下。</param>
        /// <returns>返回执行结果。</returns>
        public static bool Sorted(T category, bool isDown)
        {
            if(Database.Sorted(category.TableName, "CategoryID", category.CategoryID, "ParentID, SortOrder", isDown, "ParentID = @ParentID AND CultureName = @CultureName", new
            {
                ParentID = category.ParentID,
                CultureName = category.CultureName
            }))
            {
                Caches.Remove(GetCacheKey(category.TableName, category.CultureName));
                return true;
            }
            return false;
        }
        #endregion

        #region modules
        /// <summary>
        /// 通过模型分组名称加载分类列表。
        /// </summary>
        /// <typeparam name="T">分类类型。</typeparam>
        /// <param name="moduleGroupKey">模型分组键。</param>
        /// <param name="cultureName">区域文化。</param>
        /// <returns>返回分类列表。</returns>
        public static List<T> LoadCategories(string moduleGroupKey, string cultureName)
        {
            var table = new T().TableName;
            string key = "Modules::Categories::" + GetCacheKey(table, cultureName);
            return Caches.Get<List<T>>(key, () =>
            {
                var categories = new List<T>();
                var modules = ContentModules.GetModules(moduleGroupKey);
                if(modules == null || modules.Count == 0)
                    return categories;
                string moduleIDs = modules.Join(",", module => string.Format("'{0}'", ((ContentModule)module).ModuleID));
                using(var reader = Database.ExecuteReader("SELECT * FROM {0} WHERE CultureName = @CultureName AND ParentID = 0 AND ModuleID{1} ORDER BY ParentID, SortOrder".FormatWith(table, moduleIDs.FormatIDs()), new { CultureName = cultureName }))
                {
                    while(reader.Read())
                    {
                        var category = reader.As<T>();
                        categories.Add(category);
                    }
                    reader.Close();
                }
                Caches.Insert(key, categories, new System.Web.Caching.CacheDependency(null, new string[] { GetCacheKey(table, cultureName) }));
                return categories;
            });
        }
        #endregion
    }
}
